﻿/**
* Copyright 2013, JackJCSN ,IIT of Guet
* Released under the Apache License 2.0
* http://flow.jackjcsn.com/About/
**/
if (!window.requestAnimationFrame)
{
    var requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame
                        || window.mozRequestAnimationFrame || window.msRequestAnimationFrame;
    if (!requestAnimationFrame)
    {
        alert("您的浏览器不受支持，请您检查您的浏览器兼容性。");
    }
    window.requestAnimationFrame = requestAnimationFrame;
}

function Engine(canva)
{
    this._self = this,
    this.canvas = canva,
    this.context = canva.getContext("2d"),
    this.Map = null,
    this.Drawed = null;

    this.Draw = function ()
    {
        //var context = document.getElementsByTagName("canvas")[0].getContext("2d");
        var context = this.context;
        context.clearRect(0, 0, 450, 450);
        context.beginPath();
        context.fillStyle = "#FFF";
        context.lineWidth = 2;
        context.strokeStyle = "#FFF"
        context.strokeRect(20, 20, 50, 50);
        context.strokeRect(20, 70, 50, 50);
        context.strokeRect(20, 120, 50, 50);
        context.strokeRect(20, 170, 50, 50);
        context.strokeRect(20, 220, 50, 50);
        context.strokeRect(70, 20, 50, 50);
        context.strokeRect(70, 70, 50, 50);
        context.strokeRect(70, 120, 50, 50);
        context.strokeRect(70, 170, 50, 50);
        context.strokeRect(70, 220, 50, 50);
        context.strokeRect(120, 20, 50, 50);
        context.strokeRect(120, 70, 50, 50);
        context.strokeRect(120, 120, 50, 50);
        context.strokeRect(120, 170, 50, 50);
        context.strokeRect(120, 220, 50, 50);
        context.strokeRect(170, 20, 50, 50);
        context.strokeRect(170, 70, 50, 50);
        context.strokeRect(170, 120, 50, 50);
        context.strokeRect(170, 170, 50, 50);
        context.strokeRect(170, 220, 50, 50);
        context.strokeRect(220, 20, 50, 50);
        context.strokeRect(220, 70, 50, 50);
        context.strokeRect(220, 120, 50, 50);
        context.strokeRect(220, 170, 50, 50);
        context.strokeRect(220, 220, 50, 50);
        context.closePath();
    },

    this.InitMap = function (map)
    {
        this.Map = JSON.parse(map);
        this.Drawed = JSON.parse(map);
        var context = this.context;
        //var context = document.getElementsByTagName("canvas")[0].getContext("2d");
        for (var i = 0; i < 5; i++)
        {
            for (var j = 0; j < 5; j++)
            {
                if (this.Map[i][j])
                {
                    try
                    {
                        context.fillStyle = this.Colors[this.Map[i][j] - 1];
                        context.beginPath();
                        context.arc(45 + i * 50, 45 + j * 50, 20, 0, 2 * Math.PI);
                        context.closePath();
                        context.fill();
                    }
                    catch (e)
                    {
                        console.warn(e);
                    }
                }
            }
        }
    }
}

//Engine.prototype.Colors = ["#FF4040", "#269926", "#1240AB", "#FFE773", "#BF7130", "#009999", "#3E0470"];
Engine.prototype.Colors = ["#CB3725", "#2C9A42", "#006098", "#FBE369", "#E15200", "#00ADBC", "#330099"];

Engine.Marks = [0, "A", "B", "C", "D", "E", "F", "G"];

Engine.prototype.VSync = true;

Engine.prototype.CumputePipe = function (engin)
{
    var _self = this;
    if (!(this instanceof Engine))
    {
        _self = engin;
    }
    var t = 0;
    for (var i = 0; i < 5; i++)
    {
        for (var j = 0; j < 5; j++)
        {
            if (_self.Drawed[i][j])
            {
                t++;
            }
        }
    }
    var p = parseInt(t / 25 * 100)
    $("#pipe").text(p);
    return p;
}

Engine.prototype.Search = function (mark, engin)
{
    var _self = this;
    if (!(this instanceof Engine))
    {
        _self = engin;
    }

    for (var i = 0; i < 5; i++)
    {
        for (var j = 0; j < 5; j++)
        {
            if (engin.Map[i][j] === mark)
            {
                return { x: i, y: j };
            }
        }
    }
    return { x: -1, y: -1 };
}

Engine.prototype.FindFlow = function (pos, engin)
{
    var _self = this;
    if (!(this instanceof Engine))
    {
        _self = engin;
    }
    var p = { x: pos.x, y: pos.y };
    var I = _self.Map[p.x][p.y];
    var M = Engine.Marks[I];
    var go = true;
    var find = [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]];
    while (go)
    {
        if ((p.y + 1) < 5)
        {
            p.y++;

            if (_self.Map[p.x][p.y] === I)
            {
                return true;
            }
            if (_self.Drawed[p.x][p.y] === M)
            {
                finded.push(p);
                continue;
            }
        }

        if ((p.x - 1) > 0)
        {
            p.x--;

            if (_self.Map[p.x][p.y] === I)
            {
                return true;
            }
            if (_self.Drawed[p.x][p.y] === M)
            {
                finded.push(p);
                continue;
            }

        }

        if ((p.y - 1) > 0)
        {
            p.y--;

            if (_self.Map[p.x][p.y] === I)
            {
                return true;
            }
            if (_self.Drawed[p.x][p.y] === M)
            {
                finded.push(p);
                continue;
            }

        }

        if ((p.x + 1) < 5)
        {
            p.x++;

            if (_self.Map[p.x][p.y] === I)
            {
                return true;
            }
            if (_self.Drawed[p.x][p.y] === M)
            {
                finded.push(p);
                continue;
            }
        }
        go = false;
    }
    return false;
}

Engine.prototype.CumputeFlow = function (engin)
{
    var _self = this;
    if (!(this instanceof Engine))
    {
        _self = engin;
    }
    var n = parseInt($("#flows").text());
    var f = 0;
    for (var i = 0; i < n; i++)
    {
        var P = _self.Search(i + 1, _self);
        if (P.x != -1)
        {
            try
            {
                if (_self.FindFlow(P))
                {
                    f++;
                }
            }
            catch (ex)
            {
            }
        }
    }
    $("#currentflow").text(f);
    return f / n;
}

Engine.prototype.FPS = 30;

Engine.log = function (x, y)
{
    $("#coordinates").text(x + "," + y);
}

Engine.DrawAnimation = function (startX, startY, endX, endY, engin)
{
    var canvas = engin.canvas;
    var context = engin.context;
    var sPos = engin.Positions[startY][startX];
    var ePos = engin.Positions[endY][endX];
    var color = engin.Map[startX][startY] || Engine.Marks.indexOf(engin.Drawed[startX][startY]);

    //context.strokeStyle = color ? engin.Colors[color - 1] : "#FFF";
    context.lineWidth = 20;
    context.beginPath();
    context.moveTo(sPos.x, sPos.y);
    context.lineTo(ePos.x, ePos.y);
    context.stroke();
    context.closePath();
    if (startX == endX)
    {
        if (startY > endY)
        {
            var t = endY;
            endY = startY;
            startY = t;
        }
        var m = endY - startY;
        for (var i = 0; i < m + 1; i++)
        {
            if (!(engin.Drawed[startX][startY + i] instanceof Number))
            {
                engin.Drawed[startX][startY + i] = Engine.Marks[color];
            }
        }
    }
    if (startY == endY)
    {
        if (startX > endX)
        {
            var t = endX;
            endX = startX;
            startX = t;
        }
        var m = endX - startX;
        for (var i = 0; i < m + 1; i++)
        {
            if (!(engin.Drawed[startX][startY + i] instanceof Number))
            {
                engin.Drawed[startX + i][startY] = Engine.Marks[color];
            }
        }
    }
    var p = engin.CumputePipe();
    var flow = engin.CumputeFlow(engin);
    if (p === 100)
    {
        alert("Good Job!");
    }
}

Engine.prototype.Positions = [[{ x: 45, y: 45 }, { x: 95, y: 45 }, { x: 145, y: 45 }, { x: 195, y: 45 }, { x: 245, y: 45 }],
                           [{ x: 45, y: 95 }, { x: 95, y: 95 }, { x: 145, y: 95 }, { x: 195, y: 95 }, { x: 245, y: 95 }],
                           [{ x: 45, y: 145 }, { x: 95, y: 145 }, { x: 145, y: 145 }, { x: 195, y: 145 }, { x: 245, y: 145 }],
                           [{ x: 45, y: 195 }, { x: 95, y: 195 }, { x: 145, y: 195 }, { x: 195, y: 195 }, { x: 245, y: 195 }],
                           [{ x: 45, y: 245 }, { x: 95, y: 245 }, { x: 145, y: 245 }, { x: 195, y: 245 }, { x: 245, y: 245 }]];

Engine.Transform = function (A, B)
{
    if (A < 20)
    {
        A = 20
    }
    if (B < 20)
    {
        B = 20;
    }
    if (A > 245)
    {
        A = 245
    }
    if (B > 245)
    {
        B = 245
    }
    var pos = { x: A, y: B };

    pos.x = parseInt((pos.x - 20) / 50);
    pos.y = parseInt((pos.y - 20) / 50);
    Engine.log(pos.x, pos.y);
    return pos;
}

Engine.prototype.addCavansListener = function (engin)
{
    var cav = $(engin.canvas);
    var prePos = { x: 0, y: 0 }
    prePos = Engine.Transform(prePos.x, prePos.y);

    cav.bind("mousedown", function (e)
    {
        prePos.x = e.offsetX;
        prePos.y = e.offsetY;

        prePos = Engine.Transform(prePos.x, prePos.y);
        var color = engin.Map[prePos.x][prePos.y] || Engine.Marks.indexOf(engin.Drawed[prePos.x][prePos.y]);
        engin.context.strokeStyle = color ? engin.Colors[color - 1] : "#FFF";
        cav.mousemove(function (ev)
        {
            //context.restore();
            x = ev.offsetX;
            y = ev.offsetY;
            cav.css("cursor", "hand");

            //console.log(x + "," + y);
            var Pos = Engine.Transform(x, y);

            Engine.DrawAnimation(prePos.x, prePos.y, Pos.x, Pos.y, engin);
            e.stopPropagation();
            e.preventDefault();
            document.selection &&
            document.selection.empty &&
            (document.selection.empty(), 1) ||
            window.getSelection && window.getSelection().removeAllRanges();
            prePos = Engine.Transform(x, y);
        });
    });

    $(window).bind("mouseup", function (e)
    {
        cav.unbind("mousemove");
        cav.css("cursor", "default");
    });

    //try
    //{
    //    cav.bind("touchstart", function (e)
    //    {
    //        //context.restore();
    //        var evt = e.originalEvent;
    //        var touch = evt.touches[0];
    //        x = touch.clientX - touch.target.offsetLeft;
    //        y = touch.clientY - touch.target.offsetTop;
    //        var Pos = Engine.Transform(x, y);
    //        prePos = Pos;
    //    });
    //    cav.bind("touchmove", function (e)
    //    {
    //        //context.restore();
    //        var evt = e.originalEvent;
    //        var touch = evt.touches[0];
    //        x = touch.clientX - touch.target.offsetLeft;
    //        y = touch.clientY - touch.target.offsetTop;
    //        var Pos = Engine.Transform(x, y);
    //        Engine.DrawAnimation(prePos.x, prePos.y, Pos.x, Pos.y, engin);
    //        e.stopPropagation();
    //        e.preventDefault();
    //        prePos = Pos;
    //    });
    //}
    //catch (ex)
    //{
    //}
}